/**********************************************
*  Classes:   SceneNode
*  Desc:      Abstract class that defines a node
*			  in the Scene Graph
*  Author:    Vaios Kalpias-Ilias (C) 2008-2009
***********************************************/

#ifndef SCENENODE_H
#define SCENENODE_H

#include <list>
#include <string>
#include "SmartPointer.h"

class SceneNode;
SmartPointer(SceneNode);

class SceneNode
{
public:

	// types fo nodes
	typedef enum node_type_e
	{
		NODE_DEFAULT,
		NODE_TRANSFORM,
		NODE_GEOMETRY,
		NODE_MESH,
		NODE_CAMERA,
		NODE_BILLBOARD,
		NODE_PARTICLESYSTEM,
		NODE_PARTICLE

	}NodeType;

	SceneNode();
	virtual ~SceneNode();

	// delete memory
	//void Release() { delete this; }

	// update children
	void Update();

	// detach all children from node
	void DetachAllChildren();

	// detach the node from its parent
	void DetachParent();

	// add child to the list
	void AttachChild (SceneNodePtr node);

	// remove child from the list
	void DetachChild (SceneNodePtr node);


	const std::string& GetName() const
	{
		return m_sName;
	}

	
	void SetName(const std::string& name)
	{
		m_sName = name;
	}

	SceneNode* GetParent() const
	{
		return m_pParent;
	}

	virtual const NodeType GetType() const = 0;
		
	typedef std::list<SceneNodePtr> NodeList;
	const NodeList& GetChildren() const
	{
		return m_lChildren;
	}


	// simple RTTI
	const bool DerivesFromTransform() const
	{
		if (GetType() == NODE_DEFAULT)
			return false;

		return true;
	}

	const bool DerivesFromGeometry() const
	{
		if (GetType() == NODE_GEOMETRY ||
			GetType() == NODE_BILLBOARD||
			GetType() == NODE_PARTICLE)
			return true;

		return false;
	}


protected:
	
	// name of node
	std::string m_sName;
	// parent
	SceneNode* m_pParent;
	// children
	std::list<SceneNodePtr> m_lChildren;

	// destroy all children
	void Destroy();

	// do something before updating
	// the children
	virtual void PreUpdate() = 0;
	// do something after updating
	// the children
	virtual void PostUpdate() = 0;

	void DestroyChild(SceneNodePtr child);

};


#endif